package com.yuuzy.service.impl;

import com.aliyun.oss.OSS;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.yuuzy.constant.MessageConstant;
import com.yuuzy.dto.PatientPageQueryDTO;
import com.yuuzy.entity.Patient;
import com.yuuzy.entity.PatientImageInfo;
import com.yuuzy.exception.ImageNotExistException;
import com.yuuzy.mapper.PatientBasicInfoMapper;
import com.yuuzy.mapper.PatientImageInfoMapper;
import com.yuuzy.mapper.PatientMapper;
import com.yuuzy.result.PageResult;
import com.yuuzy.service.ReportService;
import com.yuuzy.utils.AliOssUtil;
import com.yuuzy.vo.MonthlyDataVO;
import com.yuuzy.vo.PatientPageQueryVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.datetime.standard.DateTimeFormatterFactory;
import org.springframework.stereotype.Service;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

@Service
@Slf4j

public class ReportServiceImpl implements ReportService {
	@Autowired
	private PatientMapper patientMapper;
	@Autowired
	private PatientBasicInfoMapper patientBasicInfoMapper;
	@Autowired
	private PatientImageInfoMapper patientImageInfoMapper;
	@Autowired
	private AliOssUtil aliOssUtil;

	/**
	 * 全字段检索分页查询
	 *
	 * @param patientPageQueryDTO
	 * @return
	 */
	@Override
	public PageResult retrievalPageQuery(PatientPageQueryDTO patientPageQueryDTO) {
		PageHelper.startPage(patientPageQueryDTO.getPage(), patientPageQueryDTO.getPageSize());
		Page<PatientPageQueryVO> page = patientBasicInfoMapper.retrievalPageQuery(patientPageQueryDTO);
		return new PageResult(page.getTotal(), page.getResult());
	}

	/**
	 * 根据统计年份计算每月录入人数
	 *
	 * @param year
	 * @return
	 */
	@Override
	public MonthlyDataVO getMonthlyData(int year) {
		List<Integer> monthList = new ArrayList<>();
		//设置月份列表
		for (int i = 1; i <= 12; i++) {
			monthList.add(i);
		}
		//查询人数列表
		List<Integer> countList = patientBasicInfoMapper.getMonthlyData(year);
		return MonthlyDataVO.builder()
				.monthList(StringUtils.join(monthList, ","))
				.countList(StringUtils.join(countList, ","))
				.build();
	}

	/**
	 * 导出患者信息到Excel
	 *
	 * @param response
	 * @param patientPageQueryDTO
	 */
	@Override
	public void exportPatientInfo(HttpServletResponse response, PatientPageQueryDTO patientPageQueryDTO) {
		//1.查询数据库，获得患者信息
		List<Patient> patientList = patientMapper.retrievalQuery(patientPageQueryDTO);
		//2.通过POI将数据写入Excel中
		InputStream in = this.getClass().getClassLoader().getResourceAsStream("template/患者信息模版.xlsx");
		try {
			//基于模板文件创建一个新的Excel文件
			XSSFWorkbook excel = new XSSFWorkbook(in);
			XSSFSheet sheet = excel.getSheet("Sheet1");
			//填充时间数据
			sheet.getRow(2).createCell(0).setCellValue("生成时间：" + LocalDateTime.now().format(new DateTimeFormatterFactory("yyyy-MM-dd k:mm:ss ").createDateTimeFormatter()));
			//填充患者数据
			int rowNum = 4;
			for (Patient patient : patientList) {
				XSSFRow row = sheet.createRow(rowNum++);
				int cellNum = 0;
				row.createCell(cellNum++).setCellValue(patient.getId());
				row.createCell(cellNum++).setCellValue(patient.getName() != null ? patient.getName() : "");
				row.createCell(cellNum++).setCellValue(patient.getGender() != null ? convertToGender(patient.getGender()) : "");
				row.createCell(cellNum++).setCellValue(patient.getAge() != null ? patient.getAge().toString() : "");
				row.createCell(cellNum++).setCellValue(patient.getTreatmentDate() != null ? String.valueOf(patient.getTreatmentDate()) : "");
				row.createCell(cellNum++).setCellValue(patient.getTreatmentLoc() != null ? convertToLoc(patient.getTreatmentLoc()) : "");
				row.createCell(cellNum++).setCellValue(patient.getRevi() != null ? convertToBoolean(patient.getRevi()) : "");
				row.createCell(cellNum++).setCellValue(patient.getBirthday() != null ? String.valueOf(patient.getBirthday()) : "");
				row.createCell(cellNum++).setCellValue(patient.getEthnicity() != null ? patient.getEthnicity() : "");
				row.createCell(cellNum++).setCellValue(patient.getPhone() != null ? patient.getPhone() : "");
				row.createCell(cellNum++).setCellValue(patient.getLocation() != null ? patient.getLocation() : "");
				row.createCell(cellNum++).setCellValue(patient.getMaritalStatus() != null ? convertToBoolean(patient.getMaritalStatus()) : "");
				row.createCell(cellNum++).setCellValue(patient.getNativePlace() != null ? patient.getNativePlace() : "");
				row.createCell(cellNum++).setCellValue(patient.getJob() != null ? convertToJob(patient.getJob()) : "");
				row.createCell(cellNum++).setCellValue(patient.getInsurance() != null ? convertToInsurance(patient.getInsurance()) : "");
				row.createCell(cellNum++).setCellValue(patient.getInformant() != null ? convertToInformant(patient.getInformant()) : "");
				row.createCell(cellNum++).setCellValue(patient.getChiefComplaint() != null ? patient.getChiefComplaint() : "");
				row.createCell(cellNum++).setCellValue(patient.getInquirer() != null ? patient.getInquirer() : "");
				row.createCell(cellNum++).setCellValue(patient.getConstitutionTypeGrade() != null ? convertToGrade(patient.getConstitutionTypeGrade()) : "");
				row.createCell(cellNum++).setCellValue(patient.getTendencyConstitutionType() != null ? patient.getTendencyConstitutionType() : "");
				row.createCell(cellNum++).setCellValue(patient.getPresentIllness() != null ? patient.getPresentIllness() : "");
				row.createCell(cellNum++).setCellValue(patient.getPastHistory() != null ? patient.getPastHistory() : "");
				row.createCell(cellNum++).setCellValue(patient.getFamilyHistory() != null ? patient.getFamilyHistory() : "");
				row.createCell(cellNum++).setCellValue(patient.getAllergyHistory() != null ? patient.getAllergyHistory() : "");
				row.createCell(cellNum++).setCellValue(patient.getHeight());
				row.createCell(cellNum++).setCellValue(patient.getWeight());
				row.createCell(cellNum++).setCellValue(patient.getMentalEmotion() != null ? patient.getMentalEmotion() : "");
				row.createCell(cellNum++).setCellValue(patient.getSleepQuality() != null ? patient.getSleepQuality() : "");
				row.createCell(cellNum++).setCellValue(patient.getAppetite() != null ? patient.getAppetite() : "");
				row.createCell(cellNum++).setCellValue(patient.getDefecationFrequency() != null ? patient.getDefecationFrequency().toString() : "");
				row.createCell(cellNum++).setCellValue(patient.getDefecationIntervalDays() != null ? patient.getDefecationIntervalDays().toString() : "");
				row.createCell(cellNum++).setCellValue(patient.getStoolShape() != null ? patient.getStoolShape() : "");
				row.createCell(cellNum++).setCellValue(patient.getUrinationFrequency() != null ? patient.getUrinationFrequency() : "");
				row.createCell(cellNum++).setCellValue(patient.getUrineVolume() != null ? patient.getUrineVolume() : "");
				row.createCell(cellNum++).setCellValue(patient.getMenstrualStatus() != null ? convertToStatus(patient.getMenstrualStatus()) : "");
				row.createCell(cellNum++).setCellValue(patient.getMenarcheAge() != null ? patient.getMenarcheAge().toString() : "");
				row.createCell(cellNum++).setCellValue(patient.getMenopauseDate() != null ? String.valueOf(patient.getMenopauseDate()) : "");
				row.createCell(cellNum++).setCellValue(patient.getMenstrualPeriod() != null ? patient.getMenstrualPeriod().toString() : "");
				row.createCell(cellNum++).setCellValue(patient.getMenstrualCycle() != null ? patient.getMenstrualCycle().toString() : "");
				row.createCell(cellNum++).setCellValue(patient.getMenstrualRegular() != null ? convertToBoolean(patient.getMenstrualRegular()) : "");
				row.createCell(cellNum++).setCellValue(patient.getMenstrualVolume() != null ? convertToBoolean(patient.getMenstrualVolume()) : "");
				row.createCell(cellNum++).setCellValue(patient.getPulse() != null ? patient.getPulse().toString() : "");
				row.createCell(cellNum++).setCellValue(patient.getBreath() != null ? patient.getBreath().toString() : "");
				row.createCell(cellNum++).setCellValue(patient.getSbp() != null ? patient.getSbp().toString() : "");
				row.createCell(cellNum++).setCellValue(patient.getDbp() != null ? patient.getDbp().toString() : "");
				row.createCell(cellNum++).setCellValue(patient.getBim());
				row.createCell(cellNum++).setCellValue(patient.getWaist());
				row.createCell(cellNum++).setCellValue(patient.getHip());
				row.createCell(cellNum++).setCellValue(patient.getTongueShape() != null ? patient.getTongueShape() : "");
				row.createCell(cellNum++).setCellValue(patient.getTongueColor() != null ? patient.getTongueColor() : "");
				row.createCell(cellNum++).setCellValue(patient.getTongueCoating() != null ? patient.getTongueCoating() : "");
				row.createCell(cellNum++).setCellValue(patient.getSublingualVein() != null ? patient.getSublingualVein() : "");
				row.createCell(cellNum++).setCellValue(patient.getTongueOther() != null ? patient.getTongueOther() : "");
				row.createCell(cellNum++).setCellValue(patient.getTonguePulse() != null ? patient.getTonguePulse() : "");
				row.createCell(cellNum++).setCellValue(patient.getOtherPhysicalExamination() != null ? patient.getOtherPhysicalExamination() : "");
				row.createCell(cellNum++).setCellValue(patient.getOtherAuxiliaryExamination() != null ? patient.getOtherAuxiliaryExamination() : "");
				row.createCell(cellNum++).setCellValue(patient.getPreliminaryDiagnosis() != null ? patient.getPreliminaryDiagnosis() : "");
				row.createCell(cellNum++).setCellValue(patient.getTreatmentMeasures() != null ? patient.getTreatmentMeasures() : "");
				row.createCell(cellNum++).setCellValue(patient.getMentalEmotionComparison() != null ? convertToCompare(patient.getMentalEmotionComparison()) : "");
				row.createCell(cellNum++).setCellValue(patient.getCurrentMentalEmotion() != null ? patient.getCurrentMentalEmotion() : "");
				row.createCell(cellNum++).setCellValue(patient.getSleepComparison() != null ? convertToCompare(patient.getSleepComparison()) : "");
				row.createCell(cellNum++).setCellValue(patient.getCurrentSleepCondition() != null ? patient.getCurrentSleepCondition() : "");
				row.createCell(cellNum++).setCellValue(patient.getAppetiteComparison() != null ? convertToCompare(patient.getAppetiteComparison()) : "");
				row.createCell(cellNum++).setCellValue(patient.getCurrentAppetiteCondition() != null ? patient.getCurrentAppetiteCondition() : "");
				row.createCell(cellNum++).setCellValue(patient.getDefecationComparison() != null ? convertToCompare(patient.getDefecationComparison()) : "");
				row.createCell(cellNum++).setCellValue(patient.getCurrentDefecationCondition() != null ? patient.getCurrentDefecationCondition() : "");
				row.createCell(cellNum++).setCellValue(patient.getUrinationComparison() != null ? convertToCompare(patient.getUrinationComparison()) : "");
				row.createCell(cellNum++).setCellValue(patient.getCurrentUrinationCondition() != null ? patient.getCurrentUrinationCondition() : "");

			}

			//3.通过输出流将Excel文件下载到浏览器中
			ServletOutputStream out = response.getOutputStream();
			excel.write(out);
			//关闭资源
			in.close();
			excel.close();
			out.close();
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * 根据患者id导出图片
	 *
	 * @param id
	 * @param response
	 */
	@Override
	public void exportImagesById(Integer id, HttpServletResponse response) {
		//1.根据患者id查询数据库，获取图片url
		PatientImageInfo patientImageInfo = patientImageInfoMapper.selectById(id);
		if (patientImageInfo.getFaceImage() == null && patientImageInfo.getTongueImage() == null
				&& patientImageInfo.getPreviousScanpicture() == null && patientImageInfo.getThisTimeScanpicture() == null) {
			// 如果未找到患者图片信息，抛出异常
			throw new ImageNotExistException(MessageConstant.IMAGE_NOT_EXIST);
		}
		//2.将获得的url写入zip，并传输给前端
		// 设置响应头
		response.setContentType("application/zip");
		response.setHeader("Content-Disposition", "attachment; filename=\"" + id + "_images.zip\"");
		//创建zip文件
		try (ZipOutputStream zos = new ZipOutputStream(response.getOutputStream())) {
			//获取OSS客户端
			OSS ossClient = aliOssUtil.creatOssClient();

			// 遍历图片URL列表，将每个图片文件添加到ZIP文件中
			String imageUrl;
			//处理门诊病历
			if (patientImageInfo.getThisTimeScanpicture() != null) {
				imageUrl = patientImageInfo.getThisTimeScanpicture();
				writeImageToZip(zos, ossClient, imageUrl);
			}
			//处理舌面图像
			if (patientImageInfo.getTongueImage() != null) {
				imageUrl = patientImageInfo.getTongueImage();
				writeImageToZip(zos, ossClient, imageUrl);
			}
			//处理既往病历
			if (patientImageInfo.getPreviousScanpicture() != null) {
				imageUrl = patientImageInfo.getPreviousScanpicture();
				writeImageToZip(zos, ossClient, imageUrl);
			}
			//处理面部图像
			if (patientImageInfo.getFaceImage() != null) {
				imageUrl = patientImageInfo.getFaceImage();
				writeImageToZip(zos, ossClient, imageUrl);
			}
			//关闭OSS客户端
			ossClient.shutdown();

			// 完成ZIP文件的创建
			zos.finish();
		} catch (IOException e) {
			throw new RuntimeException("导出患者图片异常", e);// 处理异常
		}
	}

	/**
	 * 导出所有患者图片
	 *
	 * @param response
	 * @param patientPageQueryDTO
	 */
	@Override
	public void exportImages(HttpServletResponse response, PatientPageQueryDTO patientPageQueryDTO) {
		//1.查询数据库，获得患者信息
		List<PatientImageInfo> patientImageInfoList = patientMapper.selectPatientImages(patientPageQueryDTO);
		//2.写入zip文件
		// 设置响应头
		response.setContentType("application/zip");
		response.setHeader("Content-Disposition", "attachment; filename=\"patients_images.zip\"");

		// 创建 ZIP 文件
		try (ZipOutputStream zos = new ZipOutputStream(response.getOutputStream())) {
			//获取OSS客户端
			OSS ossClient = aliOssUtil.creatOssClient();
			// 遍历患者图片信息集合
			for (PatientImageInfo patientImageInfo : patientImageInfoList) {
				// 创建患者文件夹
				String folderName = patientImageInfo.getId() + "." + patientImageInfo.getName() + "-" + patientImageInfo.getUid();
				zos.putNextEntry(new ZipEntry(folderName + "/"));

				// 写入该患者的图片
				if (patientImageInfo.getThisTimeScanpicture() != null) {
					writeImageToZip(zos, ossClient, folderName, patientImageInfo.getThisTimeScanpicture());
				}
				if (patientImageInfo.getTongueImage() != null) {
					writeImageToZip(zos, ossClient, folderName, patientImageInfo.getTongueImage());
				}
				if (patientImageInfo.getPreviousScanpicture() != null) {
					writeImageToZip(zos, ossClient, folderName, patientImageInfo.getPreviousScanpicture());
				}
				if (patientImageInfo.getFaceImage() != null) {
					writeImageToZip(zos, ossClient, folderName, patientImageInfo.getFaceImage());
				}

			}
			//关闭OSS客户端
			ossClient.shutdown();
			// 完成 ZIP 文件的创建
			zos.finish();
		} catch (IOException e) {
			throw new RuntimeException("导出患者图片异常", e);
		}
	}

	/**
	 * 向zip文件中写入图片（单个患者）
	 *
	 * @param zos
	 * @param ossClient
	 * @param imageUrl
	 * @throws IOException
	 */
	private void writeImageToZip(ZipOutputStream zos, OSS ossClient, String imageUrl) throws IOException {
		// 从图片URL中获取图片文件名
		String fileName = imageUrl.substring(imageUrl.lastIndexOf('/') + 1);
		// 在ZIP文件中创建一个新条目
		zos.putNextEntry(new ZipEntry(fileName));
		// 将图片文件写入ZIP文件
		try (InputStream inputStream = aliOssUtil.getImageInputStream(ossClient, fileName)) {
			byte[] buffer = new byte[1024];
			int len;
			while ((len = inputStream.read(buffer)) > 0) {
				zos.write(buffer, 0, len);
			}
			inputStream.close();// 数据读取完成后，获取的流必须关闭，否则会造成连接泄漏，导致请求无连接可用，程序无法正常工作。
			zos.closeEntry();
		}
	}

	/**
	 * 向zip文件中写入图片（所有患者）
	 *
	 * @param zos
	 * @param ossClient
	 * @param folderName
	 * @param imageUrl
	 * @throws IOException
	 */
	private void writeImageToZip(ZipOutputStream zos, OSS ossClient, String folderName, String imageUrl) throws IOException {
		String fileName = imageUrl.substring(imageUrl.lastIndexOf('/') + 1);
		zos.putNextEntry(new ZipEntry(folderName + "/" + fileName));
		try (InputStream inputStream = aliOssUtil.getImageInputStream(ossClient, fileName)) {
			byte[] buffer = new byte[1024];
			int len;
			while ((len = inputStream.read(buffer)) > 0) {
				zos.write(buffer, 0, len);
			}
			inputStream.close();
			zos.closeEntry();
		}
	}

	/**
	 * 用于格式化就诊地点判断输出
	 *
	 * @param input
	 * @return
	 */
	private String convertToLoc(Integer input) {
		if (input == 1) {
			return "国医堂";
		} else if (input == 2) {
			return "弘医堂";
		} else {
			return "无法识别";
		}
	}


	/**
	 * 用于格式化性别判断输出
	 *
	 * @param input
	 * @return
	 */
	private String convertToGender(Integer input) {
		if (input == 0) {
			return "男";
		} else if (input == 1) {
			return "女";
		} else {
			return "无法识别";
		}
	}

	/**
	 * 用于格式化是否判断输出
	 *
	 * @param input
	 * @return
	 */
	private String convertToBoolean(Integer input) {
		if (input == 0) {
			return "否";
		} else if (input == 1) {
			return "是";
		} else {
			return "无法识别";
		}
	}

	/**
	 * 用于格式化工作类型判断输出
	 *
	 * @param input
	 * @return
	 */
	private String convertToJob(Integer input) {
		if (input == 1) {
			return "管理类：国家机关";
		} else if (input == 2) {
			return "专业技术人员";
		} else if (input == 3) {
			return "办事人员和有关人员";
		} else if (input == 4) {
			return "商业、服务业人员";
		} else if (input == 5) {
			return "农、林、牧、渔生产人员";
		} else if (input == 6) {
			return "生产、运输设备操作人员及有关人员";
		} else if (input == 7) {
			return "军人";
		} else if (input == 8) {
			return "其他";
		} else {
			return "无法识别";
		}
	}

	/**
	 * 用于格式化医保类型判断输出
	 *
	 * @param input
	 * @return
	 */
	private String convertToInsurance(Integer input) {
		if (input == 1) {
			return "公费医疗";
		} else if (input == 2) {
			return "城镇职工医保";
		} else if (input == 3) {
			return "城镇居民医保";
		} else if (input == 4) {
			return "新农合";
		} else if (input == 5) {
			return "无（长期自费）";
		} else {
			return "无法识别";
		}
	}

	/**
	 * 用于格式化供史者判断输出
	 *
	 * @param input
	 * @return
	 */
	private String convertToInformant(Integer input) {
		if (input == 1) {
			return "本人";
		} else if (input == 2) {
			return "亲属";
		} else if (input == 3) {
			return "其他陪护";
		} else {
			return "无法识别";
		}
	}

	/**
	 * 用于格式化体质指数判断输出
	 *
	 * @param input
	 * @return
	 */
	private String convertToGrade(Integer input) {
		if (input == 1) {
			return "大于60分";
		} else if (input == 2) {
			return "50-59分";
		} else if (input == 3) {
			return "40-49分";
		} else if (input == 4) {
			return "40分以下";
		} else {
			return "无法识别";
		}
	}

	/**
	 * 用于格式化月经状态判断输出
	 *
	 * @param input
	 * @return
	 */
	private String convertToStatus(Integer input) {
		if (input == 1) {
			return "未来月经";
		} else if (input == 2) {
			return "正常";
		} else if (input == 3) {
			return "绝经";
		} else {
			return "无法识别";
		}
	}

	/**
	 * 用于格式化复诊比较判断输出
	 *
	 * @param input
	 * @return
	 */
	private String convertToCompare(Integer input) {
		if (input == 1) {
			return "改善";
		} else if (input == 2) {
			return "持平";
		} else if (input == 3) {
			return "变差";
		} else {
			return "无法识别";
		}
	}
}
